/**
*
* FP mixed
* see <a href="{@docRoot}/Documentation/scheduler.html"> for more information</a>
*  Copyright (c) 2009 Ecole Centrale de Nantes IRCCyN
* @author: richard
* @version 3.2
*/
package storm.Schedulers;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Stack;
import java.util.TreeMap;
import java.util.Vector;

import storm.EvtContext;
import storm.Processors.Processor;
import storm.Schedulers.FP_P_FIFO_Scheduler.ordering_priority;
import storm.Tasks.Task;
/**
 * 
 * @author richard
 *
 */
public class FP_M_Scheduler extends Scheduler {
	/**
	 * 
	 * @author richard
	 *
	 */
	class ordering_priority implements Comparator{
		/**
		 * 
		 */
		public int compare(Object arg0, Object arg1) {
			// TODO Auto-generated method stub
			int a0 = ((Task)arg0).priority;
			int a1 = ((Task) arg1).priority;
			if (a0 > a1) return -1;
			else if (a1 == a0 ) return 0;
			     else return 1;
		}
	}
	/**
	 * 
	 */
	private boolean todo=false;
	private ArrayList listePriority;
	/**
	 * 
	 */
	public void init() {
		/**
		 * Création de la liste de priorité
		 */
		super.init();
		this.listePriority = new ArrayList();
	}
	/**
	 * 
	 */
	public void onUnBlock(EvtContext c){
		Task T = (Task) c.getSource();
		this.listePriority.add(T);
		todo = true;
	}
	/**
	 * 
	 */
	public void onBlock(EvtContext c){
		Task T = (Task) c.getCible();
		this.listePriority.remove(T);
		todo=true;
	}
	/**
	 * 
	 */
	public void onActivate(EvtContext c) {
		Task T =(Task) c.getCible();
		this.listePriority.add(T);
		todo=true;
	}
	public void sched() {
		// TODO Auto-generated method stub
		select();
		todo=false;
	}
	public void select() {
		/**
		 * trie de la liste
		 */
		Collections.sort(this.listePriority, new ordering_priority());
		ArrayList CPUS= this.Kernel.getTasksListeManager().getProcessors();
		int sizeCPUS= CPUS.size();
		/*
		 * preemption des tâches qui ne devrait plus être exécuter
		 */
		Iterator t = this.listePriority.iterator();
		while(t.hasNext()){
			Task T=(Task) t.next();
			if(sizeCPUS > 0 ) {
				sizeCPUS = sizeCPUS - 1;
			}
			else{
				if (T.isIsrunning()){
					int d = T.getOwnFieldIntValue("nopreempt");
					if (d!=1) T.preempt();
				}
			}
		}
		/**
		 * recuperer pile des CPUS libre
		 */
		Stack pileCPUS = new Stack();
		for (int l=0; l< CPUS.size() ; l++){
			Processor p=(Processor)CPUS.get(l);
			if (!(p.isRunning())) pileCPUS.push(p);
		}
		/**
		 * recuperer pile des tâches not running 
		 * tel que nombre tâche <= nombre de cpu libre 
		 */
		Stack pileTasks = new Stack();
		for (int l=0; (l< pileCPUS.size()) && (l<this.listePriority.size()) ; l++){
			Task T = (Task) this.listePriority.get(l);
			if (!(T.isIsrunning())) pileTasks.push(T);
			
		}
		/**
		 * affectation des tâches 
		 * 
		 */
		 while((pileCPUS.size()>0)){
			 if (pileTasks.size()==0) break;
			 Task T = (Task) pileTasks.pop();
			 Processor C = (Processor) pileCPUS.pop();
			 T.runningOn(C);
		 }
		// TODO Auto-generated method stub
	}
}
